#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         CallbackIterator.py
#
# Copyright:    Copyright (c) 2005, Faulkner Technologies
#
# Author:       James Davies
#
# Description:  Iterates over a sequence and wraps each element 
#               with the result of the specified method
#
#####################################################################

#####################################################################
#
#    CallbackIterator
#    Author: James Davies (james@mooball.com)
#
#    Lazily maps a method to each element of a sequence
#
#    (Burrowed from Hornet)    
#
#####################################################################

    

from AccessControl import ClassSecurityInfo, allow_module
from Globals import InitializeClass


def buildDict(row, fields):
    """
        Builds a dictionary out of the specified row, based on self.fields
        (The query description from the cursor)
        () => {}

        Fixme: This is a significant performance hit; Could probably do this lazily;
    """
    d_row = {}

    fields = iter( fields )

    # Grab the next value and the corrosponding field name, and map them into the dictionary
    for value in row:
        key = fields.next()

        if type(key) is dict:
            key = key['name']

        d_row[key] = value

    return d_row



allow_module("CallbackIterator") 

class CallbackIterator: 
    """
        CallbackIterator
        Iterates over a sequence and wraps each element with the result of the specified method
        
        usage:
            def myWrapperMethod(data):
                return WrapperObject( data )
            
            i = CallbackIterator( largeResultSet, myWrapperMethod )
            
            another example (Using a lambda function to save space):
            
            i = CallbackIterator( largeResultSet, lambda x: WrapperObject( x ) )
            
            
        Essentially, it's a cross between a generator and map()- the advantage being you can lazily 
        seek/slice to any point in the sequence.
    """
    security = ClassSecurityInfo()                
    security.setDefaultAccess('allow')
    
    def __init__(self, source, method, condition=None):
        self.source = source
        self.iterator = iter( source )
        self.method = method
        
    def next(self):
        row = self.iterator.next()
        return self.method( row )
    
    def __getslice__(self, start, end):        
        

        return CallbackIterator( self.source[start:end], self.method ) 
    
    def __getitem__(self, item):
        #print "__getitem__ on " + `self.source`
        return self.method( self.source[item] )
    
    def __iter__(self):
        return CallbackIterator( self.source, self.method )
    
    def __len__(self):
        return len(self.source)
    
    
InitializeClass(CallbackIterator)